﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Windows.Forms;
using System.Drawing;

namespace Kiiro.MSProjectPlugin
{
    public class PluginHelpers
    {
        #region Form 

        public static DialogResult dialogResult = DialogResult.None;

        public class PromptForm : Form
        {
            public PictureBox picLogo;
            public PictureBox picWorking;
            public Label lblWait1;
            public Label lblWait2;
            public Label lblConfirm;
            public Label lblWarning;
            public Label lblErrorMessage;
            public Label lblRetry;
            public Label lblFailure;
            public Label lblException;
            public Label lblUsername;
            public Label lblPassword;
            public Button btnExceptionClose;
            public Button btnFailureClose;
            public Button btnSubmit;
            public Button btnCancel;
            public TextBox txtPassword;
            public TextBox txtUsername;
            public TextBox txtError;

            public PromptForm()
            {
                // Form
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(405, 95);                
                this.StartPosition = FormStartPosition.CenterScreen;                
                this.Name = "Kiiro";
                this.Text = " - Kiiro | Project Sync";
                this.Icon = Icon.FromHandle(Properties.Resources.kiiro_icon.GetHicon());
                this.ResumeLayout(false);
                this.PerformLayout();
                this.ShowIcon = true;
                this.ShowInTaskbar = false;
                this.FormBorderStyle = FormBorderStyle.FixedDialog;
                this.MaximizeBox = false;
                this.MinimizeBox = false;
                this.BackColor = System.Drawing.Color.White;

                //Controls
                this.picLogo = new PictureBox();
                this.picLogo.Location = new Point(20, 20);
                this.picLogo.Size = new Size(95, 55);
                this.picLogo.Name = "picLogo";
                this.picLogo.Image = Properties.Resources.kiiro_logo;
                this.Controls.Add(picLogo);

                this.picWorking = new PictureBox();
                this.picWorking.Location = new Point(130, 60);
                this.picWorking.Size = new Size(210, 15);
                this.picWorking.Name = "picWorking";
                this.picWorking.Image = Properties.Resources.kiiro_sync;
                this.Controls.Add(picWorking);

                this.lblWait1 = new Label();
                this.lblWait1.Location = new Point(130, 20);
                this.lblWait1.Size = new Size(250, 20);
                this.lblWait1.Name = "lblWait1";
                this.lblWait1.Text = "Kiiro is updating your Project file.";
                this.lblWait1.Font = new Font("Arial", (float)10.5, FontStyle.Regular);
                this.Controls.Add(lblWait1);

                this.lblWait2 = new Label();
                this.lblWait2.Location = new Point(130, 40);
                this.lblWait2.Size = new Size(250, 20);
                this.lblWait2.Name = "lblWait2";
                this.lblWait2.Text = "This should just take a moment.";
                this.lblWait2.Font = new Font("Arial", (float)10.5, FontStyle.Regular);
                this.Controls.Add(lblWait2);

                this.lblConfirm = new Label();
                this.lblConfirm.Location = new Point(130, 20);
                this.lblConfirm.Size = new Size(250, 40);
                this.lblConfirm.Name = "lblConfirm";
                this.lblConfirm.Text = "Please confirm your username and password to complete the update.";
                this.lblConfirm.Font = new Font("Arial", (float)10.5, FontStyle.Regular);
                this.Controls.Add(lblConfirm);

                this.lblWarning = new Label();
                this.lblWarning.Location = new Point(130, 15);
                this.lblWarning.Size = new Size(250, 20);
                this.lblWarning.Name = "lblWarning";
                this.lblWarning.Text = "Can't complete the update.";
                this.lblWarning.Font = new Font("Arial", (float)12, FontStyle.Bold);
                this.lblWarning.ForeColor = ColorTranslator.FromHtml("#003399");
                this.Controls.Add(lblWarning);

                this.lblRetry = new Label();
                this.lblRetry.Location = new Point(130, 40);
                this.lblRetry.Size = new Size(250, 40);
                this.lblRetry.Name = "lblRetry";
                this.lblRetry.Text = "Your username or password is wrong.\nPlease try again.";
                this.lblRetry.Font = new Font("Arial", (float)10.5, FontStyle.Regular);
                this.Controls.Add(lblRetry);

                this.lblFailure = new Label();
                this.lblFailure.Location = new Point(130, 40);
                this.lblFailure.Size = new Size(275, 60);
                this.lblFailure.Name = "lblFailure";
                this.lblFailure.Text = "Sorry. We can't sync your Project file.\nPlease return to Kiiro and use the Forgot Password feature on the login page.";
                this.lblFailure.Font = new Font("Arial", 10, FontStyle.Regular);
                this.Controls.Add(lblFailure);

                this.btnFailureClose = new Button();
                this.btnFailureClose.Location = new Point(130, 100);
                this.btnFailureClose.Size = new Size(65, 20);
                this.btnFailureClose.Name = "btnFailureClose";
                this.btnFailureClose.Text = "Close";
                this.btnFailureClose.DialogResult = DialogResult.Cancel;
                this.btnFailureClose.Click += new EventHandler(btnCancel_Click);
                this.Controls.Add(btnFailureClose);

                this.lblUsername = new Label();
                this.lblUsername.Location = new Point(130, 73); 
                this.lblUsername.Size = new Size(75, 20);
                this.lblUsername.Name = "lblUsername";
                this.lblUsername.Text = "Username:";
                this.lblUsername.Font = new Font("Arial", 9, FontStyle.Regular);
                this.Controls.Add(lblUsername);

                this.txtUsername = new TextBox();
                this.txtUsername.Location = new Point(215, 70);
                this.txtUsername.Size = new Size(150, 20);
                this.txtUsername.Name = "txtUsername";
                this.Controls.Add(txtUsername);

                this.lblPassword = new Label();
                this.lblPassword.Location = new Point(130, 108);
                this.lblPassword.Size = new Size(75, 20);
                this.lblPassword.Name = "lblPassword";
                this.lblPassword.Text = "Password:";
                this.lblPassword.Font = new Font("Arial", 9, FontStyle.Regular);
                this.Controls.Add(lblPassword);

                this.txtPassword = new TextBox();
                this.txtPassword.Location = new Point(215, 105);
                this.txtPassword.Size = new Size(150, 20);
                this.txtPassword.Name = "txtPassword";
                this.txtPassword.PasswordChar = '•';
                this.Controls.Add(txtPassword);

                this.btnSubmit = new Button();
                this.btnSubmit.Location = new Point(215, 135);                 
                this.btnSubmit.Size = new Size(50, 20);
                this.btnSubmit.Name = "btnSubmit";
                this.btnSubmit.Text = "Submit";
                this.btnSubmit.DialogResult = DialogResult.None;
                this.btnSubmit.Click += new EventHandler(btnSubmit_Click);
                this.Controls.Add(btnSubmit);

                this.btnCancel = new Button();
                this.btnCancel.Location = new Point(300, 135); 
                this.btnCancel.Size = new Size(65, 20);
                this.btnCancel.Name = "btnCancel";
                this.btnCancel.Text = "Cancel";
                this.btnCancel.DialogResult = DialogResult.None;
                this.btnCancel.Click += new EventHandler(btnCancel_Click);
                this.Controls.Add(btnCancel);

                this.lblException = new Label();
                this.lblException.Location = new Point(130, 40);
                this.lblException.Size = new Size(275, 60);
                this.lblException.Name = "lblException";
                this.lblException.Text = "Kiiro encountered an error. Options\n  •Close the window and save again\n  •Do a \"Save As...\" to preserve changes";
                this.lblException.Font = new Font("Arial", 10, FontStyle.Regular);
                this.Controls.Add(lblException);

                this.lblErrorMessage = new Label();
                this.lblErrorMessage.Location = new Point(20, 100);
                this.lblErrorMessage.Size = new Size(100, 20);
                this.lblErrorMessage.Name = "lblErrorMessage";
                this.lblErrorMessage.Text = "Error Message";
                this.lblErrorMessage.Font = new Font("Arial", (float)10.5, FontStyle.Regular);
                this.Controls.Add(lblErrorMessage);

                this.btnExceptionClose = new Button();
                this.btnExceptionClose.Location = new Point(170, 210);
                this.btnExceptionClose.Size = new Size(65, 20);
                this.btnExceptionClose.Name = "btnExceptionClose";
                this.btnExceptionClose.Text = "Close";
                this.btnExceptionClose.DialogResult = DialogResult.Cancel;
                this.btnExceptionClose.Click += new EventHandler(btnCancel_Click);
                this.Controls.Add(btnExceptionClose);

                this.txtError = new TextBox();
                this.txtError.Location = new Point(20, 120);
                this.txtError.Size = new Size(365, 80);
                this.txtError.Name = "txtError";
                this.txtError.Multiline = true;
                this.txtError.ReadOnly = true;
                this.txtError.ScrollBars = ScrollBars.Vertical;
                this.Controls.Add(txtError);

                this.picWorking.Visible = false;
                this.lblWait1.Visible = false;
                this.lblWait2.Visible = false;
                this.lblConfirm.Visible = false;
                this.lblWarning.Visible = false;
                this.lblErrorMessage.Visible = false;
                this.lblRetry.Visible = false;
                this.lblFailure.Visible = false;
                this.lblException.Visible = false;
                this.lblUsername.Visible = false;
                this.lblPassword.Visible = false;
                this.btnExceptionClose.Visible = false;
                this.btnFailureClose.Visible = false;
                this.btnSubmit.Visible = false;
                this.btnCancel.Visible = false;
                this.txtPassword.Visible = false;
                this.txtUsername.Visible = false;
                this.txtError.Visible = false;

                this.AcceptButton = btnSubmit;
            }          

            public void Waiting()
            {
                this.picWorking.Visible = true;
                this.lblWait1.Visible = true;
                this.lblWait2.Visible = true;
                this.lblConfirm.Visible = false;
                this.lblWarning.Visible = false;
                this.lblErrorMessage.Visible = false;
                this.lblRetry.Visible = false;
                this.lblFailure.Visible = false;
                this.lblException.Visible = false;
                this.lblUsername.Visible = false;
                this.lblPassword.Visible = false;
                this.btnExceptionClose.Visible = false;
                this.btnFailureClose.Visible = false;
                this.btnSubmit.Visible = false;
                this.btnCancel.Visible = false;
                this.txtPassword.Visible = false;
                this.txtUsername.Visible = false;
                this.txtError.Visible = false;

                this.btnExceptionClose.Enabled = false;
                this.btnFailureClose.Enabled = false;
                this.btnSubmit.Enabled = false;
                this.btnCancel.Enabled = false;
                this.txtPassword.Enabled = false;
                this.txtUsername.Enabled = false;
                this.txtError.Enabled = false;

                this.ClientSize = new System.Drawing.Size(405, 95);
                this.ControlBox = false;
                this.UseWaitCursor = true;

                this.Refresh();
                Application.DoEvents();
            }

            public void Login()
            {
                this.picWorking.Visible = false;
                this.lblWait1.Visible = false;
                this.lblWait2.Visible = false;
                this.lblConfirm.Visible = true;
                this.lblWarning.Visible = false;
                this.lblErrorMessage.Visible = false;
                this.lblRetry.Visible = false;
                this.lblFailure.Visible = false;
                this.lblException.Visible = false;
                this.lblUsername.Visible = true;
                this.lblPassword.Visible = true;
                this.btnExceptionClose.Visible = false;
                this.btnFailureClose.Visible = false;
                this.btnSubmit.Visible = true;
                this.btnCancel.Visible = true;
                this.txtPassword.Visible = true;
                this.txtUsername.Visible = true;
                this.txtError.Visible = false;

                this.btnExceptionClose.Enabled = false;
                this.btnFailureClose.Enabled = false;
                this.btnSubmit.Enabled = true;
                this.btnCancel.Enabled = true;
                this.txtPassword.Enabled = true;
                this.txtUsername.Enabled = true;
                this.txtError.Enabled = false;

                this.btnCancel.Location = new Point(300, 135);
                this.btnSubmit.Location = new Point(215, 135);
                this.lblUsername.Location = new Point(130, 73); 
                this.txtUsername.Location = new Point(215, 70); 
                this.lblPassword.Location = new Point(130, 108); 
                this.txtPassword.Location = new Point(215, 105);

                this.txtUsername.Text = "";
                this.txtPassword.Text = "";                                
                this.btnSubmit.Focus();                

                this.ClientSize = new System.Drawing.Size(405, 170);
                this.ControlBox = false;
                this.UseWaitCursor = false;

                this.Refresh();
                Application.DoEvents();
                this.txtUsername.Select();

                while (dialogResult == DialogResult.None && this.Visible)
                { Application.DoEvents(); }
            }

            public void Retry()
            {
                this.picWorking.Visible = false;
                this.lblWait1.Visible = false;
                this.lblWait2.Visible = false;
                this.lblConfirm.Visible = false;
                this.lblWarning.Visible = true;
                this.lblErrorMessage.Visible = false;
                this.lblRetry.Visible = true;
                this.lblFailure.Visible = false;
                this.lblException.Visible = false;
                this.lblUsername.Visible = true;
                this.lblPassword.Visible = true;
                this.btnExceptionClose.Visible = false;
                this.btnFailureClose.Visible = false;
                this.btnSubmit.Visible = true;
                this.btnCancel.Visible = true;
                this.txtPassword.Visible = true;
                this.txtUsername.Visible = true;
                this.txtError.Visible = false;

                this.btnExceptionClose.Enabled = false;
                this.btnFailureClose.Enabled = false;
                this.btnSubmit.Enabled = true;
                this.btnCancel.Enabled = true;
                this.txtPassword.Enabled = true;
                this.txtUsername.Enabled = true;
                this.txtError.Enabled = false;
                
                this.btnCancel.Location = new Point(300, 150);                
                this.btnSubmit.Location = new Point(215, 150);
                this.lblUsername.Location = new Point(130, 88); 
                this.txtUsername.Location = new Point(215, 85); 
                this.lblPassword.Location = new Point(130, 123); 
                this.txtPassword.Location = new Point(215, 120);

                this.txtUsername.Text = "";
                this.txtPassword.Text = "";                                
                this.btnSubmit.Focus();

                this.ClientSize = new System.Drawing.Size(405, 180);
                this.ControlBox = false;
                this.UseWaitCursor = false;

                this.Refresh();
                Application.DoEvents();
                this.txtUsername.Select();

                while (dialogResult == DialogResult.None && this.Visible)
                { Application.DoEvents(); }
            }

            public void Fail()
            {
                this.picWorking.Visible = false;
                this.lblWait1.Visible = false;
                this.lblWait2.Visible = false;
                this.lblConfirm.Visible = false;
                this.lblWarning.Visible = true;
                this.lblErrorMessage.Visible = false;
                this.lblRetry.Visible = false;
                this.lblFailure.Visible = true;
                this.lblException.Visible = false;
                this.lblUsername.Visible = false;
                this.lblPassword.Visible = false;
                this.btnExceptionClose.Visible = false;
                this.btnFailureClose.Visible = true;
                this.btnSubmit.Visible = false;
                this.btnCancel.Visible = false;
                this.txtPassword.Visible = false;
                this.txtUsername.Visible = false;
                this.txtError.Visible = false;

                this.btnExceptionClose.Enabled = false;
                this.btnFailureClose.Enabled = true;
                this.btnSubmit.Enabled = false;
                this.btnCancel.Enabled = false;
                this.txtPassword.Enabled = false;
                this.txtUsername.Enabled = false;
                this.txtError.Enabled = false;                

                this.btnFailureClose.Focus();

                this.ClientSize = new System.Drawing.Size(405, 135);
                this.ControlBox = true;
                this.UseWaitCursor = false;

                this.Refresh();
                Application.DoEvents();

                while (dialogResult == DialogResult.None && this.Visible)
                { Application.DoEvents(); }
                dialogResult = DialogResult.None;
                this.DialogResult = DialogResult.None;
            }

            public void Exception(Exception ex)
            {
                this.picWorking.Visible = false;
                this.lblWait1.Visible = false;
                this.lblWait2.Visible = false;
                this.lblConfirm.Visible = false;
                this.lblWarning.Visible = true;
                this.lblErrorMessage.Visible = true;
                this.lblRetry.Visible = false;
                this.lblFailure.Visible = false;
                this.lblException.Visible = true;
                this.lblUsername.Visible = false;
                this.lblPassword.Visible = false;
                this.btnExceptionClose.Visible = true;
                this.btnFailureClose.Visible = false;
                this.btnSubmit.Visible = false;
                this.btnCancel.Visible = false;
                this.txtPassword.Visible = false;
                this.txtUsername.Visible = false;
                this.txtError.Visible = true;

                this.btnExceptionClose.Enabled = true;
                this.btnFailureClose.Enabled = false;
                this.btnSubmit.Enabled = false;
                this.btnCancel.Enabled = false;
                this.txtPassword.Enabled = false;
                this.txtUsername.Enabled = false;
                this.txtError.Enabled = true;

                this.btnExceptionClose.Focus();
                this.txtError.Text = ex.Message;

                this.ClientSize = new System.Drawing.Size(405, 240);
                this.ControlBox = true;
                this.UseWaitCursor = false;

                this.Refresh();
                Application.DoEvents();

                while (dialogResult == DialogResult.None && this.Visible)
                { Application.DoEvents(); }
                dialogResult = DialogResult.None;
                this.DialogResult = DialogResult.None;
            }
        }     

        static void btnCancel_Click(object sender, EventArgs e)
        {
            dialogResult = DialogResult.Cancel;
        }

        static void btnSubmit_Click(object sender, EventArgs e)
        {
            dialogResult = DialogResult.OK;
        }

        #endregion

        private static string universalTime = System.Globalization.DateTimeFormatInfo.InvariantInfo.UniversalSortableDateTimePattern;
        private static DateTime validStart = new DateTime(1984, 1, 1);
        private static DateTime validFinish = new DateTime(2049, 12, 31);

        public class Service
        {
            public string Name;
            public string Path;
            public int UserId;
            public ICredentials Credentials;            
            public Cookie Cookie;
            public XmlDocument OldTasks = new XmlDocument();

            public Service(string name, string path)
            {
                this.Name = name;
                this.Path = path;                
            }
        }

        public static string GetServiceUrl(string path)
        {
            string serviceUrl = string.Empty;

            string[] serviceArray = path.Split("/".ToCharArray(), StringSplitOptions.None);
            
            for (int i = 0; i < serviceArray.Length - 2; i++)
            {
                serviceUrl += serviceArray[i] + "/";
            }

            serviceUrl += "_vti_bin/KiiroServices.asmx";

            return serviceUrl;
        }

        public static string GetAuthenticationUrl(string path)
        {

            string serviceUrl = string.Empty;

            string[] serviceArray = path.Split("/".ToCharArray(), StringSplitOptions.None);

            for (int i = 0; i < serviceArray.Length - 2; i++)
            {
                serviceUrl += serviceArray[i] + "/";
            }

            serviceUrl += "_vti_bin/Authentication.asmx";

            return serviceUrl;
        }


        public class ProjectHolder
        {
            public string Description;
            public string SummaryNote;
        }

        public class TaskHolder
        {
            public List<string> AssignedToList = new List<string>();
            public string AssignedWork;
            public string PercentComplete;
            public string Title;
            public string Description;
            public string StatusNote;
            public string StartDate;
            public string EndDate;
            public string PlanId;
            public string OutLineNumber;
            public string MidoriId;
            public string ParentTasks;
        }

        internal static XmlDocument TaskToXml(XmlDocument doc, MSProject.Task task)
        {
            XmlElement midori = doc.DocumentElement;            

            XmlElement xmlTasks = doc.DocumentElement;
            XmlNode xmlTask = CreateNode("Task", doc);

            XmlNode assignedToList = CreateNode("AssignedToList", doc);
            foreach (MSProject.Resource resource in task.Resources)
                assignedToList.AppendChild(CreateNode("AssignedTo", doc, resource.Name.ToString()));
            xmlTask.AppendChild(assignedToList);
                        
            xmlTask.AppendChild(CreateNode("ParentTasks", doc, GetParents(task)));
            xmlTask.AppendChild(CreateNode("AssignedWork", doc, task.Work.ToString()));
            xmlTask.AppendChild(CreateNode("PercentageComplete", doc, task.PercentComplete.ToString()));
            xmlTask.AppendChild(CreateNode("Title", doc, task.Name));
            xmlTask.AppendChild(CreateNode("Description", doc, task.Notes));
            xmlTask.AppendChild(CreateNode("StatusNote", doc, task.Text10));            
            xmlTask.AppendChild(CreateNode("StartDate", doc, DateTime.Parse(task.Start.ToString()).ToString(universalTime)));
            xmlTask.AppendChild(CreateNode("EndDate", doc, DateTime.Parse(task.Finish.ToString()).ToString(universalTime)));
            xmlTask.AppendChild(CreateNode("PlanId", doc, task.UniqueID.ToString()));
            xmlTask.AppendChild(CreateNode("OutLineNumber", doc, task.OutlineNumber.ToString()));
            xmlTask.AppendChild(CreateNode("MidoriId", doc, task.Text9.ToString()));

            xmlTasks.AppendChild(xmlTask);

            return doc;
        }

        internal static XmlNode CreateNode(string nodeName, XmlDocument xmlDoc)
        {
            XmlNode node = xmlDoc.CreateNode(XmlNodeType.Element, nodeName, "");
            return node;
        }

        internal static XmlNode CreateNode(string nodeName, XmlDocument xmlDoc, string innerText)
        {
            XmlNode newNode = CreateNode(nodeName, xmlDoc);
            newNode.InnerText = innerText;
            return newNode;
        }

        private static string GetParents(MSProject.Task task)
        {
            string parent = string.Empty;

            if (task.OutlineParent.OutlineNumber != "0")
            {
                MSProject.Task parentTask = (MSProject.Task)task.OutlineParent;
                if (task.OutlineParent.OutlineNumber != "1")
                    parent += GetParents(parentTask) + " > " + parentTask.Name;
                else if (task.OutlineParent.OutlineNumber == "1")
                    parent += parentTask.Name;                
            }

            return parent;
        }

        internal static XmlDocument ProjectToXml(MSProject.Project project)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<Project></Project>");
            XmlElement xmlProject = doc.DocumentElement;
            
            xmlProject.AppendChild(CreateNode("StartDate", doc, DateTime.Parse(project.ProjectStart.ToString()).ToString(universalTime)));
            xmlProject.AppendChild(CreateNode("EndDate", doc, DateTime.Parse(project.ProjectFinish.ToString()).ToString(universalTime)));
            xmlProject.AppendChild(CreateNode("Description", doc, project.Notes));
            xmlProject.AppendChild(CreateNode("SummaryNote", doc, project.Text10));
            XmlNode teamMembers = CreateNode("TeamMembers", doc);
            foreach (MSProject.Resource resource in project.Resources)
                teamMembers.AppendChild(CreateNode("Member", doc, resource.Name));
            xmlProject.AppendChild(teamMembers);

            return doc;
        }

        internal static void UpdateProject(MSProject.Project project, XmlDocument xmlMidori)
        {
            XmlNode projectNode = xmlMidori.DocumentElement.SelectSingleNode("Project");
            project.Notes = projectNode.SelectSingleNode("Description").InnerText;
            project.Text10 = projectNode.SelectSingleNode("SummaryNote").InnerText;
            if (ValidDate(DateTime.Parse(projectNode.SelectSingleNode("ProjectStart").InnerText).ToUniversalTime()))
                project.ProjectStart = DateTime.Parse(projectNode.SelectSingleNode("ProjectStart").InnerText).ToUniversalTime();
            if (ValidDate(DateTime.Parse(projectNode.SelectSingleNode("ProjectFinish").InnerText).ToUniversalTime()))
                project.ProjectFinish = DateTime.Parse(projectNode.SelectSingleNode("ProjectFinish").InnerText).ToUniversalTime();

            XmlNode teamMembersNode = xmlMidori.DocumentElement.SelectSingleNode("TeamMembers");

            foreach (XmlNode teamMember in teamMembersNode.ChildNodes)
            {
                bool resourceExists = false;
                foreach (MSProject.Resource resource in project.Resources)
                {
                    if (resource.Name == teamMember.InnerText)
                        resourceExists = true;
                }

                if (!resourceExists)
                    project.Resources.Add(teamMember.InnerText, project.Resources.Count + 1);
            }
        }

        internal static void UpdateTasks(MSProject.Project project, XmlDocument xmlMidori)
        {
            List<TaskHolder> taskHolders = new List<TaskHolder>();

            try
            {
                taskHolders = PopulateTHList(xmlMidori);

                foreach (MSProject.Task task in project.Tasks)
                {
                    if (task != null && task.OutlineChildren.Count == 0)
                    {
                        bool isDeleted = true;
                        foreach (TaskHolder taskHolder in taskHolders)
                        {
                            if (task.UniqueID.ToString() == taskHolder.PlanId)
                            {
                                isDeleted = false;

                                #region Update Task 
                                foreach (string assignedTo in taskHolder.AssignedToList)
                                {
                                    bool assigned = false;
                                    bool newResource = true;
                                    foreach (MSProject.Resource resource in project.Resources)
                                    {
                                        if (assignedTo == resource.Name)
                                        {
                                            newResource = false;
                                            foreach (MSProject.Assignment assignment in task.Assignments)
                                            {
                                                if (assignment.ResourceName.ToString() == assignedTo)
                                                {
                                                    assigned = true;
                                                    break;
                                                }
                                            }

                                            if (!assigned)
                                            {
                                                MSProject.Assignment newAssignment = task.Assignments.Add(task.ID, resource.ID, 1);
                                            }
                                        }
                                    }

                                    if (newResource)
                                    {
                                        MSProject.Assignment newAssignment = task.Assignments.Add(task.ID, project.Resources.Add(assignedTo, project.Resources.Count + 1).ID, 1);
                                    }
                                }

                                foreach(MSProject.Resource resource in task.Resources)
                                {
                                    bool assigned = false;
                                    assigned = taskHolder.AssignedToList.Exists(x => x == resource.Name);                                    

                                    if (!assigned)
                                        resource.Delete();
                                }

                                if (ValidDate(DateTime.Parse(taskHolder.StartDate).ToUniversalTime()))
                                    task.Start = DateTime.Parse(taskHolder.StartDate).ToUniversalTime();
                                else
                                    task.Start = project.ProjectStart;

                                if (ValidDate(DateTime.Parse(taskHolder.EndDate).ToUniversalTime()))
                                    task.Finish = DateTime.Parse(taskHolder.EndDate).ToUniversalTime();
                                else
                                    task.Finish = project.ProjectFinish;
 
                                task.Work = taskHolder.AssignedWork;                                
                                task.PercentComplete = taskHolder.PercentComplete;                                                               

                                task.Name = taskHolder.Title;
                                task.Notes = taskHolder.Description;
                                task.Text10 = taskHolder.StatusNote;
                                task.ConstraintDate = "NA";
                                task.ConstraintType = "As Soon As Possible";
                                #endregion
                                break;
                            }
                        }

                        if (isDeleted)
                        {
                            #region Delete Task 
                            task.Delete();
                            #endregion
                        }
                    }
                }
                #region Add Task 

                foreach (TaskHolder taskHolder in taskHolders)
                {
                    bool isNew = true;
                    foreach (MSProject.Task task in project.Tasks)
                    {
                        if (task != null && task.OutlineChildren.Count == 0 && task.UniqueID.ToString() == taskHolder.PlanId)
                        {
                            isNew = false;
                            break;
                        }
                    }

                    if (isNew)
                    {
                        MSProject.Task newTask = project.Tasks.Add(taskHolder.Title, project.Tasks.Count + 1);
                        newTask.Notes = taskHolder.Description;
                        newTask.Text9 = taskHolder.MidoriId;
                        newTask.Text10 = taskHolder.StatusNote;                        
                        foreach (string assignedTo in taskHolder.AssignedToList)
                        {
                            bool assigned = false;
                            foreach (MSProject.Resource resource in project.Resources)
                            {
                                if (assignedTo == resource.Name)
                                {
                                    MSProject.Assignment newAssignment = newTask.Assignments.Add(newTask.ID, resource.ID, 1);                                    
                                    assigned = true;
                                    break;
                                }
                            }

                            if (!assigned)
                            {
                                MSProject.Assignment newAssignment = newTask.Assignments.Add(newTask.ID, project.Resources.Add(assignedTo, project.Resources.Count + 1).ID, 1);
                            }
                        }

                        if ( ValidDate ( DateTime.Parse ( taskHolder.StartDate ).ToUniversalTime ( ) ) )
                            newTask.Start = DateTime.Parse(taskHolder.StartDate).ToUniversalTime();
                        else
                            newTask.Start = project.ProjectStart;

                        if ( ValidDate ( DateTime.Parse ( taskHolder.EndDate ).AddHours ( 24.00 ).ToUniversalTime ( ) ) )
                            newTask.Finish = DateTime.Parse(taskHolder.EndDate).AddHours ( 24.00 ).ToUniversalTime();
                        else
                            newTask.Finish = project.ProjectFinish;

                        newTask.Work = taskHolder.AssignedWork;
                        newTask.PercentComplete = taskHolder.PercentComplete;

                        newTask.ConstraintDate = "NA";
                        newTask.ConstraintType = "As Soon As Possible";

                        while (newTask.OutlineParent.Name != project.Tasks[1].OutlineParent.Name)                        
                            newTask.OutlineOutdent();                        
                    }
                }

                #endregion
            }            
            catch(Exception ex)
            {
                throw ex;
            }
        }

        internal static List<TaskHolder> PopulateTHList(XmlDocument xmlMidori)
        { 
            List<TaskHolder> taskHolders = new List<TaskHolder>();

            XmlNode taskNodes = xmlMidori.DocumentElement.SelectSingleNode("Tasks");
            foreach(XmlNode xmlTask in taskNodes.ChildNodes)
                taskHolders.Add(PopulateTH(xmlTask));            

            return taskHolders;
        }

        internal static TaskHolder PopulateTH(XmlNode xmlTask)
        {
            TaskHolder taskHolder = new TaskHolder();

            foreach (XmlNode assignedTo in xmlTask.SelectSingleNode("AssignedToList").ChildNodes)            
                taskHolder.AssignedToList.Add(assignedTo.InnerText);

            taskHolder.ParentTasks = xmlTask.SelectSingleNode("ParentTasks") != null ? xmlTask.SelectSingleNode("ParentTasks").InnerText : null;
            taskHolder.AssignedWork = xmlTask.SelectSingleNode("AssignedWork").InnerText;
            taskHolder.PercentComplete = xmlTask.SelectSingleNode("PercentageComplete").InnerText;
            taskHolder.Title = xmlTask.SelectSingleNode("Title").InnerText;
            taskHolder.Description = xmlTask.SelectSingleNode("Description").InnerText;
            taskHolder.StatusNote = xmlTask.SelectSingleNode("StatusNote").InnerText;
            taskHolder.StartDate = xmlTask.SelectSingleNode("StartDate").InnerText;
            taskHolder.EndDate = xmlTask.SelectSingleNode("EndDate").InnerText;
            taskHolder.PlanId = xmlTask.SelectSingleNode("PlanId").InnerText;
            taskHolder.OutLineNumber =  xmlTask.SelectSingleNode("OutLineNumber") != null ? xmlTask.SelectSingleNode("OutLineNumber").InnerText : null;
            taskHolder.MidoriId = xmlTask.SelectSingleNode("MidoriId").InnerText;
                                           
            return taskHolder;
        }

        internal static XmlDocument FindChanges(XmlDocument oldTasks, MSProject.Project project)
        {            
            List<TaskHolder> oldTHs = new List<TaskHolder>();
            XmlDocument allTasks = new XmlDocument();
            allTasks.LoadXml("<Tasks></Tasks>");
            int count = 0;

            #region Parse Xml Tasks 

            if (oldTasks.DocumentElement != null)
            {
                foreach (XmlNode node in oldTasks.DocumentElement.ChildNodes)
                {
                    oldTHs.Add(PopulateTH(node));
                }
            }

            #endregion

            try
            {
                foreach (TaskHolder oldTask in oldTHs)
                {
                    bool oldDeleted = true;
                    foreach (MSProject.Task task in project.Tasks)
                    {
                        if (task != null && task.OutlineChildren.Count == 0)
                        {
                            count++;

                            #region Updated Tasks

                            if (task.UniqueID.ToString() == oldTask.PlanId)
                            {
                                oldDeleted = false;
                                bool updated = false;
                                if (task.Work.ToString() != oldTask.AssignedWork || task.Text10 != oldTask.StatusNote || task.OutlineNumber.ToString() != oldTask.OutLineNumber ||
                                    task.PercentComplete.ToString() != oldTask.PercentComplete || task.Notes != oldTask.Description || task.Name != oldTask.Title || GetParents(task) != oldTask.ParentTasks ||
                                    DateTime.Parse(task.Finish.ToString()).ToString(universalTime) != oldTask.EndDate || DateTime.Parse(task.Start.ToString()).ToString(universalTime) != oldTask.StartDate)
                                {
                                    updated = true;
                                }

                                bool resourceFound = false;
                                if (!updated)
                                {
                                    foreach (MSProject.Resource resource in task.Resources)
                                    {
                                        resourceFound = false;
                                        resourceFound = oldTask.AssignedToList.Exists(x => x == resource.Name);                                        
                                        if (!resourceFound)
                                            updated = true;
                                    }
                                }

                                if (!updated)
                                {
                                    foreach (string oldResource in oldTask.AssignedToList)
                                    {                                        
                                        resourceFound = false;
                                        foreach (MSProject.Resource resource in task.Resources)
                                        {
                                            if (oldResource == resource.Name)
                                                resourceFound = true;
                                        }
                                        if (!resourceFound)
                                            updated = true;
                                    }
                                }

                                if (updated)
                                {
                                    allTasks = TaskToXml(allTasks, task, "updated");
                                }
                                break;
                            }

                            #endregion
                        }
                    }
                    if (oldDeleted)
                    {
                        #region Deleted Tasks

                        allTasks = THToXml(allTasks, oldTask, "deleted");

                        #endregion
                    }
                }

                #region Added Tasks

                foreach (MSProject.Task task in project.Tasks)
                {
                    if (task != null && task.OutlineChildren.Count == 0)
                    {
                        bool newTask = true;
                        newTask = !oldTHs.Exists(x => x.PlanId == task.UniqueID.ToString());                        
                        if (newTask)
                            allTasks = TaskToXml(allTasks, task, "added");
                    }
                }

                #endregion
            }
            catch(Exception ex)
            {
                throw ex;
            }

            return allTasks;
        }

        internal static XmlDocument TaskToXml(XmlDocument doc, MSProject.Task task, string key)
        {
            XmlElement xmlTasks = doc.DocumentElement;
            XmlNode xmlTask = CreateNode("Task", doc);

            XmlNode assignedToList = CreateNode("AssignedToList", doc);
            foreach (MSProject.Resource resource in task.Resources)
                assignedToList.AppendChild(CreateNode("AssignedTo", doc, resource.Name.ToString()));
            xmlTask.AppendChild(assignedToList);

            xmlTask.AppendChild(CreateNode("ParentTasks", doc, GetParents(task)));
            xmlTask.AppendChild(CreateNode("AssignedWork", doc, task.Work.ToString()));
            xmlTask.AppendChild(CreateNode("PercentageComplete", doc, task.PercentComplete.ToString()));
            xmlTask.AppendChild(CreateNode("Title", doc, task.Name));
            xmlTask.AppendChild(CreateNode("Description", doc, task.Notes));
            xmlTask.AppendChild(CreateNode("StatusNote", doc, task.Text10)); 
            xmlTask.AppendChild(CreateNode("StartDate", doc, DateTime.Parse(task.Start.ToString()).ToString(universalTime)));
            xmlTask.AppendChild(CreateNode("EndDate", doc, DateTime.Parse(task.Finish.ToString()).ToString(universalTime)));
            xmlTask.AppendChild(CreateNode("PlanId", doc, task.UniqueID.ToString()));
            xmlTask.AppendChild(CreateNode("Key", doc, key));
            xmlTask.AppendChild(CreateNode("MidoriId", doc, task.Text9.ToString()));

            xmlTasks.AppendChild(xmlTask);

            return doc;
        }

        internal static XmlDocument THToXml(XmlDocument doc, TaskHolder task, string key)
        {
            XmlElement xmlTasks = doc.DocumentElement;
            XmlNode xmlTask = CreateNode("Task", doc);

            XmlNode assignedToList = CreateNode("AssignedToList", doc);
            foreach (string resource in task.AssignedToList)
                assignedToList.AppendChild(CreateNode("AssignedTo", doc, resource.ToString()));
            xmlTask.AppendChild(assignedToList);

            xmlTask.AppendChild(CreateNode("AssignedWork", doc, task.AssignedWork.ToString()));
            xmlTask.AppendChild(CreateNode("PercentageComplete", doc, task.PercentComplete.ToString()));
            xmlTask.AppendChild(CreateNode("Title", doc, task.Title));
            xmlTask.AppendChild(CreateNode("Description", doc, task.Description));
            xmlTask.AppendChild(CreateNode("StatusNote", doc, task.StatusNote));
            xmlTask.AppendChild(CreateNode("StartDate", doc, task.StartDate.ToString()));
            xmlTask.AppendChild(CreateNode("EndDate", doc, task.EndDate.ToString()));
            xmlTask.AppendChild(CreateNode("PlanId", doc, task.PlanId.ToString()));
            xmlTask.AppendChild(CreateNode("Key", doc, key));
            xmlTask.AppendChild(CreateNode("MidoriId", doc, task.MidoriId.ToString()));

            xmlTasks.AppendChild(xmlTask);

            return doc;
        }

        private static bool ValidDate(DateTime checkDate)
        {
            bool valid = true;

            if (checkDate < validStart || checkDate > validFinish)
                valid = false;

            return valid;
        }
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.MSProjectPlugin/PluginHelpers.cs $
 * 
 * 13    11/19/09 10:09a Shafia
 * 
 * 12    30/10/09 2:28p Camerons
 * 
 * 11    10/27/09 5:35p Adamw
 * accomodations for moving plan file to document library:
 * -added IsProjectPlan to Documents list
 * -changed regex in plugin to allow for new path
 * -changed the method to getProject to use GetByRelativeUrl
 * -changed web service urls to allow for new path
 * 
 * 10    10/02/09 1:13p Stefanf
 * 
 * 9     10/02/09 10:46a Stefanf
 * 
 * 8     17/08/09 10:45a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/